package main

import (
	"bufio"
	"fmt"
	"log"
	"modbus-go-demo/utils/tools"
	"net"
	"strings"
	"time"
)

// Modbus TCP 服务端,slave端代码
// 响应poll端请求

const BYTE_LENGTH = 4096      // 单次循环最大读取的字节数量, 如果单次发送的数据包大于这里, 则需要多次读取
const MIN_PACKAGE_LENGTH = 15 // 最小数据包的长度

var userNum int

type Client struct {
	RemoteAddr   string // 客户端 IP + 端口
	Connection   net.Conn
	Reader       *bufio.Reader
	CreateTime   time.Time // 连接时间
	LastDataTime time.Time // 最近一次接收数据的时间
}

var OnlineMap map[string]*Client
var register chan *Client
var unregister chan *Client
var timeoutKick int

func main() {
	timeoutKick = 60
	OnlineMap = make(map[string]*Client)
	register = make(chan *Client, 100)
	unregister = make(chan *Client, 100)
	serverPort := "502"
	go connManage()
	listener, err := net.Listen("tcp", ":"+serverPort)
	if err != nil {
		log.Fatal("tcp 服务启动失败 " + err.Error())
	}
	fmt.Printf("%-32s%-32s\n", "tcp listen on "+serverPort, "OK")
	for {
		conn, err2 := listener.Accept()
		if err2 != nil {
			fmt.Println("listener Accept Error", err2)
			break
		}
		remoteAddr := conn.RemoteAddr().String()
		reader := bufio.NewReader(conn)
		newClient := &Client{
			RemoteAddr:   remoteAddr,
			Connection:   conn,
			Reader:       reader,
			CreateTime:   time.Now(),
			LastDataTime: time.Now(),
		}
		register <- newClient
		userNum++
		//_ = conn.SetReadDeadline(time.Now().Add(10 * time.Second))
		go handleCon(newClient)
	}
}

func handleCon(client *Client) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("handleCon Error: ", err)
		}
		unregister <- client
	}()

	remoteAddr := client.Connection.RemoteAddr().String() // 客户端IP:PORT

	var buffer [BYTE_LENGTH]byte
	for {
		n, err := client.Connection.Read(buffer[0:])
		if err != nil {
			if err == net.ErrClosed || strings.Contains(err.Error(), "use of closed network connection") || strings.Contains(err.Error(), "read: connection reset by peer") || strings.Contains(err.Error(), "forcibly closed") {
				fmt.Printf("[%s ~ %s]# 连接已关闭或重置\n", tools.GetNow(), remoteAddr)
			} else {
				fmt.Println("unknown read error: ", err.Error())
			}
			return
		}
		register <- client

		str := tools.ByteArrayToHexStr(buffer[0:n])
		fmt.Printf("[%s ~ %s]# %v\n", tools.GetNow(), remoteAddr, buffer[0:n])
		_ = tools.WriteStringToFile(fmt.Sprintf("[%s ~ %s]# %s", tools.GetNow(), remoteAddr, str), "raw_data.log", "")
		/* --- 处理 rawData 开始 --- */

		/* --- 处理 rawData 结束 --- */
		clearBuffer(&buffer, n)

	}
}

// 连接管理, 检查连接是否在线, 删除离线的client
func connManage() {
	// 连接和断开管理
	go func() {
		for {
			select {
			case client := <-register:
				_, ok := OnlineMap[client.RemoteAddr]
				if !ok {
					fmt.Printf("[%s ~ %s]# 新客户端已连接 %s\n", tools.GetNow(), client.RemoteAddr, "WELL")
				}
				client.LastDataTime = time.Now()
				OnlineMap[client.RemoteAddr] = client
			case client := <-unregister:
				fmt.Printf("用户掉线 %s\n", client.RemoteAddr)
				_ = client.Connection.Close()
				delete(OnlineMap, client.RemoteAddr)
			}
		}
	}()

	// 超过一定时间未发送数据, 自动算离线
	//go func() {
	//	for {
	//		// 1秒一次循环判断, 删除最后一次发送数据的时间大于5秒的client
	//		time.Sleep(1 * time.Second)
	//		now := time.Now()
	//		for _, client := range OnlineMap {
	//			if now.Sub(client.LastDataTime) > time.Duration(timeoutKick)*time.Second {
	//				fmt.Println("客户端长时间未发送数据, 已掉线: ", client.RemoteAddr)
	//				unregister <- client
	//			}
	//		}
	//	}
	//}()
}

// bytesEqual 比较两个字节切片是否相等
func bytesEqual(a, b []byte) bool {
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

// 判断 suffix 是否能和 data 结尾衔接, 找到最长重叠部分的起始索引
func matchSuffix(data []byte, suffix []byte) (index int, b bool) {
	b = false
	index = -1
	var len1 = len(data)
	var len2 = len(suffix)
	if len1 < len2 {
		return
	}

	for i := 1; i < len2; i++ {
		if bytesEqual(suffix[0:i], data[len1-i:]) {
			b = true
			index = len1 - i
		}
	}
	return
}

// 重置rawData
func resetRawData(rawData []byte, toIndex int) []byte {
	if len(rawData) > toIndex {
		rawData = rawData[toIndex:]
	} else {
		rawData = make([]byte, 0)
	}
	return rawData
}

func clearBuffer(buf *[BYTE_LENGTH]byte, n int) {
	if n >= BYTE_LENGTH {
		n = BYTE_LENGTH
	}
	for i := 0; i < n; i++ {
		buf[i] = 0
	}
}
